﻿using System.Collections.Concurrent;

namespace MyTRCP.Common
{
    public class BlockingQueue<T>
    {
        private readonly ConcurrentQueue<T> _queue;
        private readonly ManualResetEvent _manualResetEvent;
        private volatile bool _cancelTakeRequested;
        public void Clear()
        {
            _queue.Clear();
        }
        public BlockingQueue()
        {
            _queue = new ConcurrentQueue<T>();
            _manualResetEvent = new ManualResetEvent(false);
        }
        public void Add(T item)
        {
            _queue.Enqueue(item);
            _manualResetEvent.Set();
        }
        public int Count()
        {
            return _queue.Count;
        }
        public int GetCountIfAdded()
        {
            _manualResetEvent.WaitOne();
            return _queue.Count;
        }
        public int GetCountIfAddedThenReset()
        {
            _manualResetEvent.WaitOne();
            _manualResetEvent.Reset();
            return _queue.Count;
        }
        public T Take()
        {
            var isEmpty = false;
            T? item = default;
            while (true)
            {
                if (_queue.Count > 0)
                {
                    _queue.TryDequeue(out item);
                    _manualResetEvent.Reset();
                }
                else
                {
                    isEmpty = true;
                }
                if (item != null)
                    return item;
                if (isEmpty)
                {
                    _manualResetEvent.WaitOne();
                    if (_cancelTakeRequested)
                    {
                        _cancelTakeRequested = false;
                        _manualResetEvent.Reset();
                        throw new OperationCanceledException();
                    }
                }
            }
        }
        public void CancelTake()
        {
            _cancelTakeRequested = true;
            _manualResetEvent.Set();
        }
    }
}